package playbook

import (
	"encoding/json"
	"fmt"
	"sort"
	"time"

	"gddgame.cc/galaxy/binocle"
	. "gddgame.cc/galaxy/common/dsl/game"
	. "gddgame.cc/galaxy/common/dsl/game/object"
	. "gddgame.cc/galaxy/common/dsl/game/stat"
	. "gddgame.cc/galaxy/common/dsl/game/target"
	. "gddgame.cc/galaxy/common/dsl/game/task"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"
	"gddgame.cc/galaxy/utils/serialize/msgpack"
)

const (
	BaseStatKeyLength = 20
	MaxStatKeyIndex   = 100
)

type ProcessHandler func(member string, data []byte)
type ExitHandler func(player *Player)
type EventHandler func(players []*Player)

type Data struct {
	*StatData
	*ObjectData
	*TargetData

	RealtimeIndex []int
	DataStatKey   map[int]string
}

// 管理所有数据以及事件处理
type Playbook struct {
	token string

	binocle.App
	*Data

	scene Scene

	def.Serialize

	Players   []*Player          // 每个用户的信息
	PlayerMap map[string]*Player // map
	Source    map[string]int32   // 当前剧本统计信息

	team      map[string][]string // 组队信息
	languages []string            // 当前所有玩家的语言列表

	// 更新统计信息
	relationPlayer map[int64]*Player

	startHandler   []EventHandler
	finishHandler  []EventHandler
	processHandler []ProcessHandler
	exitHandler    []ExitHandler

	// 内部状态
	processResponse *responseManager
	status          bool
	dataStatIndex   map[int][]string
	taskDataIndex   []int
	taskIds         []int

	globalData         []InfoDetail
	globalDataLanguage [][]InfoDetail

	start time.Time
}

func NewPlaybook(token string, scene Scene, openIds []string, app binocle.App) *Playbook {
	//m := make(map[string]*Player, len(players))
	//for _, player := range players {
	//	m[player.OpenId] = player
	//}
	pb := &Playbook{
		token: token,

		App:  app,
		Data: scene.Data(),

		scene:     scene,
		Players:   []*Player{},
		PlayerMap: map[string]*Player{},
		Source:    map[string]int32{},

		team:      make(map[string][]string),
		languages: []string{},

		processResponse: newResponseManager(),
		status:          false,
		dataStatIndex:   make(map[int][]string),
		taskDataIndex:   []int{},
		taskIds:         []int{},

		globalData:         []InfoDetail{},
		globalDataLanguage: [][]InfoDetail{},

		relationPlayer: make(map[int64]*Player),

		processHandler: []ProcessHandler{},
		finishHandler:  []EventHandler{},
		startHandler:   []EventHandler{},
		exitHandler:    []ExitHandler{},
	}
	// 用数组传递
	pb.Serialize = msgpack.Msgpack(true)
	pb.processResponse.SetTimeout(4 * time.Second)

	tasks := pb.scene.Tasks()
	// 生成任务: 可用任务，累计任务进度
	pb.initTask(tasks)

	pb.makePlayer(openIds, false)
	return pb
}

func (pb *Playbook) OnStart(handler EventHandler) {
	pb.startHandler = append(pb.startHandler, handler)
}

func (pb *Playbook) OnProcess(handler ProcessHandler) {
	pb.processHandler = append(pb.processHandler, handler)
}

func (pb *Playbook) OnFinish(handler EventHandler) {
	pb.finishHandler = append(pb.finishHandler, handler)
}

func (pb *Playbook) OnExit(handler ExitHandler) {
	pb.exitHandler = append(pb.exitHandler, handler)
}

func (pb *Playbook) JoinMember(member string) {
	pb.makePlayer([]string{member}, false)
}

func (pb *Playbook) JoinAi(member string) {
	pb.makePlayer([]string{member}, true)
}

func (pb *Playbook) UpdateMember(member string, online bool, exit bool) {
	player, ok := pb.PlayerMap[member]
	if !ok {
		return
	}
	if pb.status && online && !player.Online {
		tasks := pb.scene.Tasks()
		// 断线重连：下发所有初始化信息
		infos := InfoArray{}
		infos = append(infos, pb.globalData...)
		// 加载语言项
		infos = append(infos, pb.globalDataLanguage[player.LanguageIndex]...)
		pb.sendPlayer(player, infos)
		pb.initPlayer(player, tasks)
		player.Online = online
	}
	if pb.status && exit && !player.Exit {
		// 直接退出
		player.Exit = exit
		player.Online = !exit
		for k := range pb.exitHandler {
			pb.exitHandler[k](player)
		}
	}
	pb.scene.Refresh(pb.Players)
}

func (pb *Playbook) UpdateProcess(member string, data []byte) {
	if !pb.status {
		return
	}
	var infos []InfoDetail
	if err := pb.Unmarshal(data, &infos); err != nil {
		return
	}

	player := pb.PlayerMap[member]
	for key := range infos {
		switch infos[key].Key {
		case RelationKey:
			// 绑定逻辑关系
			v := utils.ToInt64(infos[key].Value)
			pb.relationPlayer[v] = player
			//player.Relations[v] = nil
		case Confirm:
			// 等待当前进度所有人准备
			v := utils.ToInt(infos[key].Value)
			pb.processResponse.onResponse(v, player.OpenId, time.Now())
		case DataKey:
			v := utils.ToIntSlice(infos[key].Value)
			index := v[0]
			value := int32(v[1])
			if len(v) > 2 {
				// ai数据上报
				pi := v[2]
				player = pb.Players[pi]
			}
			updateTask := pb.isTaskIndex(player, index)
			pb.updateStat(player, index, value)
			if updateTask {
				pb.updateTaskAll()
			}
			infos := pb.scene.UpdateData()
			pb.sendOnce(infos)
		}
	}
}

func (pb *Playbook) StartTime() *time.Time {
	return &pb.start
}

func (pb *Playbook) Stop() {
	pb.status = false
}

func (pb *Playbook) Start() {
	//fmt.Println("start")
	// 初始化信息
	pb.status = true
	pb.start = time.Now()
	for k := range pb.startHandler {
		pb.startHandler[k](pb.Players)
	}
	infos := InfoArray{{Key: ServerKey, Value: &ServerInfo{Start: int(pb.start.Unix())}}}

	// 根据用户初始化场景
	infos = append(infos, pb.scene.InitScene(pb.Players)...)
	targets := pb.scene.GenerateTargetList()
	targetsIndex := make([]interface{}, len(targets)*2)
	for index, key := range targets {
		target := pb.Targets[key]
		targetsIndex[index*2] = BaseStatKeyLength + index
		targetsIndex[index*2+1] = target.Id
		groupStat := pb.TargetGroupStat[key]
		pb.dataStatIndex[BaseStatKeyLength+index] = groupStat
	}
	infos = append(infos, InfoDetail{Key: TargetDataKey, Value: targetsIndex})
	objects := pb.scene.GenerateObjectList()
	objectsIndex := make([]interface{}, len(objects)*2)
	for index, key := range objects {
		prop := pb.ObjectMap[key]
		objectsIndex[index*2] = BaseStatKeyLength + len(targets) + index
		objectsIndex[index*2+1] = prop.Id
		groupStat := pb.ObjectGroupStat[key]
		pb.dataStatIndex[BaseStatKeyLength+len(targets)+index] = groupStat
	}
	for index := range pb.dataStatIndex {
		sort.Strings(pb.dataStatIndex[index])
	}
	infos = append(infos, InfoDetail{Key: ObjectDataKey, Value: objectsIndex})

	// 下发初始化剧本
	pb.sendGlobal(infos)
	// 下发用户独立信息
	pb.NewProcess(func(data map[string]interface{}) {
		tasks := pb.scene.Tasks()
		for _, player := range pb.Players {
			pb.initPlayer(player, tasks)
		}
		// 需要先链接同步消息服务: 区域链接是用roomToken作为标识符
		stream, ctx, request, err := pb.Request("orbit").Stream("sync/single/data", pb.token)
		if err == nil {
			go func() {
				for {
					select {
					case response := <-stream:
						// data数据，进行分析解析
						if !pb.status {
							request.Finish()
							return
						}
						var data []interface{}
						_ = response.Data(&data)
						id := utils.ToInt64(data[0])
						player, ok := pb.relationPlayer[id]
						if !ok {
							continue
						}
						changeIndex := data[1].([]interface{})
						changeData := data[2].([]interface{})
						for key, i := range changeIndex {
							index := utils.ToInt(i)
							if changeData[key] == nil {
								continue
							}
							// 用于做其他处理了，非数值型
							if index > MaxStatKeyIndex {
								continue
							}
							// 实时数据过滤
							r := sort.SearchInts(pb.RealtimeIndex, index)
							if r >= 0 && r < len(pb.RealtimeIndex) && pb.RealtimeIndex[r] == index {
								continue
							}
							value := utils.ToInt32(changeData[key])
							pb.updateStat(player, index, value)
						}
					case <-ctx.Done():
						return
					}
				}
			}()
		}

		pb.OnFinish(func(players []*Player) {
			// 关闭通道
			request.Finish()
		})
		pb.NewProcess(func(data map[string]interface{}) {
			pb.Starting()
		}, "start")
	}, "init")
}

func (pb *Playbook) Starting() {
	ticker := time.NewTicker(pb.scene.Ticker())
	wait := false
	go func() {
		finish := make(chan struct{}, 1)
		pb.scene.Start(finish)
		for {
			select {
			case <-finish:
				goto Finish
			case <-ticker.C:
				if wait {
					break
				}
				if !pb.status {
					goto Finish
				}
				if !pb.updatePlayer() {
					goto Finish
				}
				infos := pb.scene.UpdateTicker(pb.languages)
				if len(infos) > 0 {
					wait = true
					pb.sendGlobal(infos)
					fmt.Println("process wait")
					pb.NewProcess(func(data map[string]interface{}) {
						wait = false
						fmt.Println("process wait finish")
					}, "ticker")
				}
			}
		}
	Finish:
		pb.status = false
		ticker.Stop()

		pb.scene.Finish(pb)
		for k := range pb.finishHandler {
			pb.finishHandler[k](pb.Players)
		}
	}()
}

// 启动新的进程，等待所有玩家响应
func (pb *Playbook) NewProcess(handler CallbackHandler, detail string) {
	num := 0
	for _, player := range pb.Players {
		if player.Exit {
			continue
		}
		if !player.Online {
			continue
		}
		if player.Ai {
			continue
		}
		num += 1
	}
	response := newResponse(handler)
	rid := pb.processResponse.addResponse(num, response)
	infos := InfoArray{{Key: Wait, Value: &ProcessDetail{Id: rid, Detail: detail}}}
	// 如果失败，再次发送：断线相当于玩家未确认
	//fmt.Println("process ", rid, detail)
	pb.sendOnce(infos)
}

// data分解语言数据
func (pb *Playbook) NewNotice(data map[string]interface{}) {
	languages := make([]InfoArray, len(pb.languages))
	for index, language := range pb.languages {
		i := data[language]
		if i == nil {
			continue
		}
		// uiPlugin直接处理json字符串
		b, err := json.Marshal(i)
		if err != nil {
			continue
		}
		languages[index] = append(languages[index], InfoDetail{Key: UiKey, Value: b})
	}
	pb.sendOnceLanguage(languages)
}

func (pb *Playbook) sendGlobal(infos InfoArray) {
	if infos != nil && len(infos) > 0 {
		languages := make([]InfoArray, len(pb.languages))
		base := InfoArray{}
		for index := range infos {
			// 分解语言数据
			if infos[index].language != nil {
				info := infos[index]
				for index := range pb.languages {
					languages[index] = append(languages[index], InfoDetail{Key: info.Key, Value: info.language[index]})
				}
			} else {
				base = append(base, infos[index])
				pb.globalData = append(pb.globalData, infos[index])
			}
		}
		for index := range pb.languages {
			pb.globalDataLanguage[index] = append(pb.globalDataLanguage[index], languages[index]...)
		}
		pb.sendOnceBase(base)
		pb.sendOnceLanguage(languages)
	}
}

func (pb *Playbook) sendOnce(infos InfoArray) {
	if infos != nil && len(infos) > 0 {
		languages := make([]InfoArray, len(pb.languages))
		base := InfoArray{}
		for index := range infos {
			// 分解语言数据
			if infos[index].language != nil {
				info := infos[index]
				for index := range pb.languages {
					languages[index] = append(languages[index], InfoDetail{Key: info.Key, Value: info.language[index]})
				}
			} else {
				base = append(base, infos[index])
			}
		}
		pb.sendOnceBase(base)
		pb.sendOnceLanguage(languages)
	}
}

func (pb *Playbook) sendOnceBase(base InfoArray) {
	if base == nil || len(base) == 0 {
		return
	}
	b, err := base.MarshalMsg(nil)
	if err != nil {
		fmt.Println("playbook base", err)
	}
	//fmt.Println("sendOnceBase", b)
	for _, player := range pb.Players {
		if !player.Online {
			continue
		}
		if player.Ai {
			continue
		}

		for k := range pb.processHandler {
			pb.processHandler[k](player.OpenId, b)
		}
	}
}

func (pb *Playbook) sendOnceLanguage(languages []InfoArray) {
	if languages == nil || len(languages) == 0 {
		return
	}
	languagesB := make([][]byte, len(languages))
	for index := range pb.languages {
		bb, err := languages[index].MarshalMsg(nil)
		if err != nil {
			fmt.Println("playbook language", err)
			continue
		}
		languagesB[index] = bb
	}
	//fmt.Println("sendOnceLanguage", languagesB)
	for _, player := range pb.Players {
		if !player.Online {
			continue
		}
		if player.Ai {
			continue
		}
		language := languagesB[player.LanguageIndex]
		if language == nil {
			continue
		}
		for k := range pb.processHandler {
			pb.processHandler[k](player.OpenId, language)
		}
	}
}

func (pb *Playbook) sendPlayer(player *Player, infos InfoArray) {
	if player.Ai {
		return
	}
	if infos != nil && len(infos) > 0 {
		languages := InfoArray{}
		base := InfoArray{}
		for index := range infos {
			// 分解语言数据
			if infos[index].language != nil {
				languages = append(languages, InfoDetail{Key: infos[index].Key, Value: infos[index].language[player.LanguageIndex]})
			} else {
				base = append(base, infos[index])
			}
		}
		if len(base) > 0 {
			b, err := base.MarshalMsg(nil)
			if err != nil {
				fmt.Println("playbook send base", err)
			}
			for k := range pb.processHandler {
				pb.processHandler[k](player.OpenId, b)
			}
		}
		if len(languages) > 0 {
			b, err := base.MarshalMsg(nil)
			if err != nil {
				fmt.Println("playbook send language", err)
			}
			for k := range pb.processHandler {
				pb.processHandler[k](player.OpenId, b)
			}
		}
	}
}

func (pb *Playbook) initPlayer(player *Player, tasks map[int]*GameTask) {
	infos := InfoArray{}
	// 下发未完成任务
	taskInfo := pb.initTaskInfo(player, tasks)
	if taskInfo != nil {
		infos = append(infos, *taskInfo)
	}
	// 当前任务进度
	infos = append(infos, pb.updateTask(player, true)...)
	// 下发玩家初始化信息
	infos = append(infos, pb.scene.InitPlayer(player)...)
	pb.sendPlayer(player, infos)
}

func (pb *Playbook) updatePlayer() bool {
	flag := false
	for key, _ := range pb.Players {
		player := pb.Players[key]
		if player.Exit {
			continue
		}
		if player.Ai {
			continue
		}
		flag = true
		// 哪个用户进度更新
		infos := pb.scene.UpdatePlayer(player)
		pb.sendPlayer(player, infos)
	}
	return flag
}

func (pb *Playbook) makePlayer(openIds []string, isAi bool) {
	for _, openId := range openIds {
		player := NewPlayer(openId)
		player.Ai = isAi
		player.LanguageIndex = -1
		player.Online = true

		player.Playbook = make(map[string]int32)

		player.Tasks = map[int]time.Time{}
		player.AvailTask = []*GameTask{}
		player.TaskProcess = map[int]*TaskProcess{}
		player.RealTaskProcess = map[int]map[string]int32{}
		player.taskDataIndex = []int{}

		pb.scene.GetPlayerInfo(player, pb.taskIds)

		// 统计所有人语言项: 确定语言索引关系
		for index, language := range pb.languages {
			if language == player.Language {
				player.LanguageIndex = index
				break
			}
		}
		if player.LanguageIndex < 0 {
			pb.languages = append(pb.languages, player.Language)
			player.LanguageIndex = len(pb.languages) - 1
			pb.globalDataLanguage = append(pb.globalDataLanguage, []InfoDetail{})
		}

		// 组队信息
		if player.TeamToken != "" {
			if _, ok := pb.team[player.TeamToken]; !ok {
				pb.team[player.TeamToken] = make([]string, 0)
			}
			pb.team[player.TeamToken] = append(pb.team[player.TeamToken], player.OpenId)
		}
		pb.Players = append(pb.Players, player)
		pb.PlayerMap[openId] = player
	}

	// 解析队伍结构
	for _, player := range pb.Players {
		if player.TeamToken == "" {
			continue
		}
		player.TeamNumber = len(pb.team[player.TeamToken])
	}
}

func (pb *Playbook) initTask(tasks map[int]*GameTask) {
	taskIds := make([]int, len(tasks))
	index := 0
	for key := range tasks {
		task := tasks[key]
		taskIds[index] = task.Id
		index += 1

		indexs := []int{}
		// 查找任务关联索引
		for _, factor := range task.Factors {
			for index, data := range pb.dataStatIndex {
				i := sort.SearchStrings(data, factor.Key)
				if i >= 0 && i < len(data) && data[i] == factor.Key {
					indexs = append(indexs, index)
				}
			}
		}
		for _, player := range pb.Players {
			player.taskDataIndex = append(player.taskDataIndex, indexs...)
		}
		pb.taskDataIndex = append(pb.taskDataIndex, indexs...)
	}

	// 去重并排序
	pb.taskDataIndex = utils.RemoveDuplicateInt(pb.taskDataIndex)
	sort.Ints(pb.taskDataIndex)
	pb.taskIds = taskIds
}

func (pb *Playbook) initTaskInfo(player *Player, tasks map[int]*GameTask) *InfoDetail {
	if player.taskDataIndex == nil {
		// 初始化任务信息
		for _, task := range tasks {
			info, ok := player.RealTaskProcess[task.Id]
			process := int32(0)
			if ok {
				for _, v := range info {
					process += v
				}
				if process == task.GetGoal() {
					continue
				}
				if task.IsAddUp {
					for key, value := range info {
						player.Playbook[key] = value
					}
				} else {
					process = 0
				}
			} else {
				realProcess := make(map[string]int32, len(task.Factors))
				player.RealTaskProcess[task.Id] = realProcess
			}

			player.TaskProcess[task.Id] = &TaskProcess{Id: task.Id, Process: process}
			player.AvailTask = append(player.AvailTask, task)
		}
		// 去重并排序
		player.taskDataIndex = utils.RemoveDuplicateInt(player.taskDataIndex)
		sort.Ints(player.taskDataIndex)
	}
	if len(player.AvailTask) > 0 {
		ids := make([]int, len(player.AvailTask))
		for index, task := range player.AvailTask {
			ids[index] = task.Id
		}
		// 统一客户端dataIndex过滤：观察者无法得知目标的dataIndex
		return &InfoDetail{Key: TaskKey, Value: &TaskDetail{Ids: ids, DataIndex: pb.taskDataIndex}}
	} else {
		return nil
	}
}

func (pb *Playbook) updateTask(player *Player, force bool) InfoArray {
	infos := InfoArray{}
	// 判断任务进度，如有更新，下发最新进度
	for _, task := range player.AvailTask {
		if !force {
			if _, ok := player.Tasks[task.Id]; ok {
				continue
			}
		}
		flag := false
		current := int32(0)
		var realProcess map[string]int32
		// 任务通过当前进度判断，如果累计，通过设置isAddUp进行存储
		if task.IsAddUp {
			realProcess = player.RealTaskProcess[task.Id]
		}
		for _, factor := range task.Factors {
			var source map[string]int32
			switch factor.Source {
			case PlaybookSource:
				source = pb.Source
			case PlaybookUserSource:
				source = player.Playbook
			default:
				continue
			}
			value := source[factor.Key]
			if value > factor.Value {
				value = factor.Value
			}
			current += value
			if task.IsAddUp {
				realProcess[factor.Key] = value
			}
		}
		// 判断进度
		process := player.TaskProcess[task.Id]
		if current != process.Process {
			flag = true
			process.Process = current
		}

		if flag && process.Process == task.GetGoal() {
			// 完成任务
			player.Tasks[task.Id] = time.Now()
		}
		//fmt.Println(task.Factors, pb.source, process, player.Tasks)
		if force || flag {
			infos = append(infos, InfoDetail{Key: TaskProcessKey, Value: process})
		}
	}
	return infos
}

func (pb *Playbook) updateTaskAll() {
	for key, _ := range pb.Players {
		player := pb.Players[key]
		if player.Exit {
			continue
		}
		if player.Ai {
			continue
		}
		infos := pb.updateTask(player, false)
		pb.sendPlayer(player, infos)
	}
}

func (pb *Playbook) stat(player *Player, key string, value int32) {
	// 记录用户自有统计
	old, ok := player.Playbook[key]
	if !ok {
		old = 0
	}
	player.Playbook[key] = value

	// 先判断是否需要统计
	stat, ok := pb.Stats[key]
	if !ok {
		return
	}
	if !stat.IsPlaybook {
		return
	}
	var tmp int32
	if stat.Type == utils.CountStat {
		// 计数型，消息顺序错误，确保值正确
		if value <= old {
			return
		}
		tmp = value - old
	} else {
		tmp = value
	}
	config := utils.StatConfig{
		Key:   key,
		Cycle: utils.AllCycle,
		Stat:  stat.Type,
	}
	// 加入playbook数据
	config.MergeStat(&pb.Source, tmp)
}

func (pb *Playbook) MaxStat() map[string][]string {
	result := make(map[string][]string)
	// 一人模式，不计算最大
	if len(pb.Players) == 1 {
		return result
	}
	// 最大战斗记录计算
	for _, stats := range pb.GameStats {
		// 获取最大值
		max := int32(0)
		maxOpenId := ""
		var maxPlayer *Player
		for key := range pb.Players {
			player := pb.Players[key]
			if player.Exit {
				continue
			}
			value := int32(0)
			// 根据依赖项统计
			for _, key := range stats.Dependents {
				if v, ok := player.Playbook[key]; ok {
					value += v
				}
			}
			// 合并关联统计项
			if !stats.IsMaxPlayer {
				player.Playbook[stats.Key] = value
				continue
			}
			if value > max {
				maxOpenId = player.OpenId
				maxPlayer = player
			}
		}
		if maxOpenId != "" && pb.judgeFactorArray(maxPlayer, stats.Factors) {
			maxPlayer.Playbook[stats.Key] = 1
			if _, ok := result[maxOpenId]; !ok {
				result[maxOpenId] = make([]string, 0)
			}
			result[maxOpenId] = append(result[maxOpenId], stats.Key)
		}
	}
	return result
}

func (pb *Playbook) isTaskIndex(player *Player, index int) bool {
	// 任务数据更新
	if len(player.taskDataIndex) > 0 {
		i := sort.SearchInts(player.taskDataIndex, index)
		if i >= 0 && i < len(player.taskDataIndex) && player.taskDataIndex[i] == index {
			return true
		}
	}
	return false
}

func (pb *Playbook) updateStat(player *Player, index int, value int32) {
	if s, ok := pb.DataStatKey[index]; ok {
		// 基础统计
		pb.stat(player, s, value)
	} else if group, ok := pb.dataStatIndex[index]; ok {
		// 游戏特定dataIndex
		for _, k := range group {
			pb.stat(player, k, value)
		}
	}
}

// 判断条件是否达成
func (pb *Playbook) judgeFactorArray(player *Player, factors [][]Factor) bool {
	for _, items := range factors {
		if pb.JudgePlayer(player, items) {
			return true
		}
	}
	return false
}

// 判断条件是否达成
func (pb *Playbook) JudgePlayer(player *Player, factors []Factor) bool {
	for _, factor := range factors {
		var source map[string]int32
		// relation是对比数字
		// source需要转化为数字条件
		switch factor.Source {
		case PlaybookSource:
			source = pb.Source
		case PlaybookUserSource:
			source = player.Playbook
		default:
			return false
		}

		if !factor.Judge(source) {
			return false
		}
	}
	return true
}

// 判断条件是否达成
func (pb *Playbook) Judge(factors []Factor) bool {
	for _, factor := range factors {
		var source map[string]int32
		// relation是对比数字
		// source需要转化为数字条件
		switch factor.Source {
		case PlaybookSource:
			source = pb.Source
		}
		if !factor.Judge(source) {
			return false
		}
	}
	return true
}

func (pb *Playbook) GetPlayerStat(player *Player, sourceKey SourceKey, key string) int32 {
	var source map[string]int32
	switch sourceKey {
	case PlaybookSource:
		source = pb.Source
	case PlaybookUserSource:
		source = player.Playbook
	}
	return source[key]
}

func (pb *Playbook) GetStat(sourceKey SourceKey, key string) int32 {
	var source map[string]int32
	switch sourceKey {
	case PlaybookSource:
		source = pb.Source
	}
	return source[key]
}
